﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Xml;
using Moonlite.ExtensionApi;

namespace Moonlite.Modules.Editors.DataTools
{
    public class XmlTreeView : TreeView
    {
        private TreeNode rootNode;
        private object lockObject = new object();
        private int osLevel = 0;
        private bool IsXPPlus
        {
            get { return OSLevel >= 510; }
        }

        private int OSLevel
        {
            get
            {
                lock (lockObject)
                {
                    if (osLevel == 0)
                    {
                        Version osVersion = Environment.OSVersion.Version;
                        if (osVersion.Major >= 6)
                        {
                            osLevel = 600;
                        }
                        else if (osVersion.Major == 5)
                        {
                            if (osVersion.Minor >= 2)
                            {
                                osLevel = 520;
                            }
                            else if (osVersion.Minor == 1)
                            {
                                osLevel = 510;
                            }
                            else
                            {
                                osLevel = 500;
                            }
                        }
                        else
                        {
                            osLevel = 1;
                        }
                    }

                    return osLevel;
                }
            }
        }

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            if (IsXPPlus)
            {
                SafeNativeMethods.SetWindowTheme(Handle, "Explorer", null);
                if (Environment.OSVersion.Version.Major >= 6)
                {
                    uint flags = (uint)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_GETEXTENDEDSTYLE, false, (int)IntPtr.Zero);
                    flags |= 0x0004;
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_SETEXTENDEDSTYLE, Convert.ToBoolean(flags), (int)flags);
                }
            }
        }

        private void AddDocumentToRootNodeCore(XmlNode node, TreeNode treeNode)
        {
            foreach (XmlNode childNode in node.ChildNodes)
            {
                if (!(childNode is XmlDeclaration))
                {
                    string attributesText = "";
                    int index = 0;
                    foreach (XmlAttribute attribute in childNode.Attributes)
                    {
                        if (index == 0)
                        {
                            attributesText = "[";
                        }

                        attributesText += attribute.Name + ": " + attribute.Value;
                        if (index != childNode.Attributes.Count - 1)
                        {
                            attributesText += ", ";
                        }
                        else
                        {
                            attributesText += "]";
                        }

                        index++;
                    }

                    TreeNode childNodeTreeNode = new TreeNode(childNode.Name + " " + attributesText, XmlTreeViewDefaultIcons.ElementIconImageIndex, XmlTreeViewDefaultIcons.ElementIconImageIndex);
                    treeNode.Nodes.Add(childNodeTreeNode);
                    if (childNode.ChildNodes.Count > 0)
                    {
                        TreeNode childrenTreeNode = new TreeNode("Children [Count: " + childNode.ChildNodes.Count.ToString() + "]", XmlTreeViewDefaultIcons.NameSpaceIconImageIndex, XmlTreeViewDefaultIcons.NameSpaceIconImageIndex);
                        childrenTreeNode.Tag = "Children";
                        childNodeTreeNode.Nodes.Add(childrenTreeNode);
                        AddDocumentToRootNodeCore(childNode, childrenTreeNode);
                        childrenTreeNode.Expand();
                    }
                }
            }
        }

        private List<TreeNode> GetAllNodesCore(TreeNode node)
        {
            List<TreeNode> nodes = new List<TreeNode>();
            foreach (TreeNode childNode in node.Nodes)
            {
                nodes.Add(childNode);
                nodes.AddRange(GetAllNodesCore(childNode));
            }

            return nodes;
        }

        public TreeNode[] GetAllNodes()
        {
            List<TreeNode> nodes = new List<TreeNode>();
            foreach (TreeNode node in Nodes)
            {
                nodes.Add(node);
                nodes.AddRange(GetAllNodesCore(node));
            }

            return nodes.ToArray();
        }

        private bool FindNode(TreeNode[] nodes, int startIndex, string text)
        {
            for (int i = startIndex; i < nodes.Length - startIndex; i++)
            {
                if (nodes[i].Text.ToUpper().Contains(text.ToUpper()) && ((string)nodes[i].Tag) != "Children")
                {
                    SelectedNode = nodes[i];
                    Select();
                    return true;
                }
            }

            return false;
        }

        public void Search(string text)
        {
            TreeNode[] nodes = GetAllNodes();
            int startIndex = 0;
            for (int i = 0; i < nodes.Length; i++)
            {
                if (nodes[i] == SelectedNode)
                {
                    startIndex = i + 1;
                }
            }

            FindNode(nodes, startIndex, text);
        }

        public void AddDocumentToRootNode(XmlDocument document, string documentRootNodeCaption)
        {
            if (document == null)
            {
                throw new NullReferenceException();
            }

            Nodes.Clear();
            rootNode = new TreeNode(documentRootNodeCaption, XmlTreeViewDefaultIcons.NameSpaceIconImageIndex, XmlTreeViewDefaultIcons.NameSpaceIconImageIndex);
            AddDocumentToRootNodeCore(document, rootNode);
            rootNode.Expand();
            Nodes.Add(rootNode);
            Sort();
        }

        public XmlTreeView()
        {
            ShowLines = false;
            ImageList = XmlTreeViewDefaultIcons.ImageList;
            TreeViewNodeSorter = new XmlTreeViewNodeSorter();
        }
    }
}
